package com.test.bendi.interceptor;


import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.test.bendi.annotation.LocalLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;


import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Aspect
@Configuration
public class LockMethodAspect {
    //最大缓存1000个，设置写缓存后5秒过期
    private static final Cache<String,Object> CACHES = CacheBuilder.newBuilder()
            .maximumSize(1000).expireAfterAccess(5, TimeUnit.SECONDS).build();

    @Around("execution(public * *(..)) && @annotation(com.test.bendi.annotation.LocalLock)")
    public Object interceptor(ProceedingJoinPoint pjp){
        MethodSignature signature = (MethodSignature)pjp.getSignature();
        Method method =signature.getMethod();
        LocalLock localLock = method.getAnnotation(LocalLock.class);
        String key = getKey(localLock.key(),pjp.getArgs());
        if(!StringUtils.isEmpty(key)){
            if(CACHES.getIfPresent(key) != null){
                throw new RuntimeException("请勿重复请求");
            }
            CACHES.put(key,key);
        }
        try{
            return pjp.proceed();
        }catch(Throwable throwable){
            throw new RuntimeException("服务器异常");
        }finally {
           // CACHES.invalidate(key);
        }
    }
    /**
     * key 的生成策略,如果想灵活可以写成接口与实现类的方式（TODO 后续讲解）
     *
     * @param keyExpress 表达式
     * @param args       参数
     * @return 生成的key
     */
    private String getKey(String keyExpress, Object[] args) {
        for (int i = 0; i < args.length; i++) {
            keyExpress = keyExpress.replace("arg[" + i + "]", args[i].toString());
        }
        return keyExpress;
    }
}
